local oo = require("SharedLibs.BaseLib")
AsyncOpInfo = require("SharedLibs.AsyncOpInfo");

Array = require("SharedLibs.Algorithem.Array");

AsyncError = oo.Class()
local AsyncError = AsyncError
AsyncError.name = "AsyncError"

function AsyncError.prototype.constructor(self, errOrStr, op, isCodeError)
	if isCodeError == nil then
		isCodeError = false
	end
	
	if type(errOrStr) == "string" then 
		self.message = errOrStr
		self._isCodeError = isCodeError
		self._opStack = AsyncError.GetOpStack(op)
		self.stack = "AsyncStack: \r " .. tostring(AsyncError._OpStackToTrace(self._opStack));
	else
		self._isCodeError = isCodeError
		self._opStack = AsyncError.GetOpStack(op)
		self._innerException = errOrStr
		self.message = self._innerException.message
		
		self.stack = (("AsyncStack: \r " .. tostring(
			AsyncError._OpStackToTrace(self._opStack)
			)) .. " \r ") .. tostring(self._innerException.stack)
	end
end

oo.SetDescriptor(
	AsyncError.prototype,
	"opStack",
	{
		get = function(self)
			return self._opStack
		end
	},
	true
)

oo.SetDescriptor(
	AsyncError.prototype,
	"innerException",
	{
		get = function(self)
			return self._innerException
		end
	},
	true
)

oo.SetDescriptor(
	AsyncError.prototype,
	"isCodeError",
	{
		get = function(self)
			return self._isCodeError
		end
	},
	true
)

function AsyncError.GetOpStackTrace(op)
	local opStack = AsyncError.GetOpStack(op);
	return AsyncError._OpStackToTrace(opStack);
end

function AsyncError._OpStackToTrace(opStack)
	local retString = ""
	opStack:ForEach(function(coInfo)
		retString = retString .. "\t"
		retString = retString .. tostring(tostring(coInfo))
		retString = retString .. "\n"
	end)

	return retString
end

function AsyncError.GetOpStack(op)
	local stack = Array.new();
	
	stack:Push(oo.New(
		AsyncOpInfo,
		op:GetDesc(),
		op.state,
		false
	));

	local parent = op.parent
	while parent ~= nil do
		stack:Push(oo.New(
			AsyncOpInfo,
			parent:GetDesc(),
			parent.state,
			false
		));
		parent = parent.parent
	end
	return stack
end


return AsyncError;
